from selenium import webdriver
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
import logging


class FindElement:
    def __init__(self, url):
        """
        初始化FindElement类的对象，启动无头Chrome浏览器并访问指定URL。

        参数:
        - url: str，要访问的网页URL。
        """
        # 使用无头模式启动Chrome浏览器
        options = webdriver.ChromeOptions()
        # options.add_argument('--headless')
        self.driver = webdriver.Chrome(options=options)
        self.driver.get(url)
        self.driver.maximize_window()

        # 配置日志记录
        logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

    # def __del__(self):
    #     """
    #     析构函数，确保WebDriver资源在对象被回收时正确释放。
    #     """
    #     self.driver.quit()

    def find_element_or_elements(self, method, element, is_single=True):
        """
        根据指定的方法和元素定位策略，查找页面上的元素或元素集合。

        参数:
        - method: selenium.webdriver.common.by.By，定位元素的方法。
        - element: str，定位元素的标识符。
        - is_single: bool，默认为True，表示是否查找单个元素。

        返回:
        - 返回定位到的单个元素或元素集合。

        抛出:
        - 当无法定位到元素时，记录错误日志。
        """
        # 将 method_str 转换为 By 枚举成员
        method_map = {
            "ID": By.ID,
            "NAME": By.NAME,
            "CLASS_NAME": By.CLASS_NAME,
            "TAG_NAME": By.TAG_NAME,
            "LINK_TEXT": By.LINK_TEXT,
            "PARTIAL_LINK_TEXT": By.PARTIAL_LINK_TEXT,
            "CSS_SELECTOR": By.CSS_SELECTOR,
            "XPATH": By.XPATH,
        }
        method = method_map.get(method.upper())
        try:
            if is_single:
                return WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((method, element)))
            else:
                return WebDriverWait(self.driver, 10).until(EC.presence_of_all_elements_located((method, element)))
        except Exception as e:
            logging.error(f"元素定位失败:{e}")

    # 以下两个方法分别用于定位单个和多个元素，通过调用find_element_or_elements实现
    def find_element(self, method, element):
        """
        定位并返回页面上的单个元素。

        参数:
        - method: selenium.webdriver.common.by.By，定位元素的方法。
        - element: str，定位元素的标识符。

        返回:
        - 定位到的单个元素。

        抛出:
        - 当无法定位到元素时，记录错误日志。
        """
        return self.find_element_or_elements(method, element, is_single=True)

    def find_elements(self, method, element):
        """
        定位并返回页面上的一组元素。

        参数:
        - method: selenium.webdriver.common.by.By，定位元素的方法。
        - element: str，定位元素的标识符。

        返回:
        - 定位到的一组元素。

        抛出:
        - 当无法定位到元素时，记录错误日志。
        """
        return self.find_element_or_elements(method, element, is_single=False)

    def select_option(self, element, option_text):
        """
        在下拉框中选择指定的选项。

        参数:
        - element: selenium.webdriver.remote.webelement.WebElement，下拉框元素。
        - option_text: str，要选择的选项的文本。

        抛出:
        - 当无法进行下拉框选择时，记录错误日志。
        """
        try:
            select = Select(element)
            select.select_by_visible_text(option_text)
        except Exception as e:
            logging.error(f"下拉框选择失败:{e}")

    def switch_to_frame(self, method, frame_locator):
        """
        切换到指定的iframe中。

        参数:
        - method: selenium.webdriver.common.by.By，定位iframe的方法。
        - frame_locator: str，定位iframe的标识符。

        抛出:
        - 当无法切换到iframe时，记录错误日志。
        """
        try:
            frame = self.find_element(method, frame_locator)
            self.driver.switch_to.frame(frame)
        except Exception as e:
            logging.error(f"切换frame失败:{e}")

    def switch_to_default_content(self):
        """
        切换回页面的默认内容（即跳出iframe）。

        抛出:
        - 当无法切换回默认内容时，记录错误日志。
        """
        try:
            self.driver.switch_to.default_content()
        except Exception as e:
            logging.error(f"返回默认frame失败:{e}")

    def confirm_alert(self, accept_or_dismiss):
        """
        处理并确认弹窗提示。

        参数:
        - accept_or_dismiss: str，指定操作，"accept"表示接受（点击确定），"dismiss"表示拒绝（点击取消）。

        抛出:
        - 当无法处理弹窗时，记录错误日志。
        """
        try:
            alert = self.driver.switch_to.alert
            if accept_or_dismiss == "accept":
                alert.accept()
            else:
                alert.dismiss()
        except Exception as e:
            logging.error(f"alert操作失败:{e}")

    # def click(self, method, element):
    #     """
    #     点击指定的元素。
    #
    #     参数:
    #     - method: selenium.webdriver.common.by.By，定位元素的方法。
    #     - element: str，定位元素的标识符。
    #
    #     抛出:
    #     - 当无法完成点击操作时，记录错误日志。
    #     """
    #     try:
    #         element = self.find_element(method, element)
    #         element.click()
    #     except Exception as e:
    #         logging.error(f"点击失败:{e}")


# a = FindElement('http://www.baidu.com')
# print(a.find_element(By.ID, 'kw').send_keys('selenium'))
